package tix

import java.io.File
import java.util.Calendar
import java.util.TimeZone
import java.text.DateFormat
import java.security.MessageDigest
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import scala.collection.immutable

// -------------------------------------------------------------------------------------------------

object Global {
  private val cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"))

  /** Reports UTC time, as a string. */
  def now(): String = {
    return "%04d%02d%02d-%02d%02d%02d-%03dUTC".format(
      cal.get(Calendar.YEAR),
      cal.get(Calendar.MONTH),
      cal.get(Calendar.DAY_OF_MONTH),
      cal.get(Calendar.HOUR),
      cal.get(Calendar.MINUTE),
      cal.get(Calendar.SECOND),
      cal.get(Calendar.MILLISECOND))
  }

  /** Throw-away files. */
  val tmpDir = new File("/tmp")

  /** Where to unpack sources. */
  val sourceDir = new File("/Source")

  /** Where to build sources. */
  val buildDir = new File("/Build")

  /** Where to install binaries. */
  val installDir = new File("/Library")

  /** Location of Gentoo source archives. */
  private val gentooDistFiles = new File("/usr/portage/distfiles")

  /** Location of local copies of source archives. */
  private val localSourceDir = new File("/Source")

  /** All locations where to look for source archives. */
  val sourcePackageDirs = List(localSourceDir, gentooDistFiles)

  def locateSource(src: File): File = {
    if (src.isAbsolute) {
      assert(src.exists)
      return src
    }
    val srcName = src.toString
    for (dir <- sourcePackageDirs) {
      val path = new File(dir, srcName)
      if (path.exists)
        return path
    }
    assert(false)
    return null
  }

  def njobs = 4
}

// -------------------------------------------------------------------------------------------------

class Config(val conf: Map[Symbol, Any]) extends Serializable {
}

// -------------------------------------------------------------------------------------------------


//object AutotoolsWorkflow extends itf.WorkflowFactory {
//  def New(pkg: itf.PackageVersion): AutotoolsWorkflow = new AutotoolsWorkflow(pkg)
//}

// -------------------------------------------------------------------------------------------------

/**
 * All packages extend this class.
 *
 * Package GCC is a singleton inheriting from this.
 * Each package has a collection of versions.
 * Each version can be instantiated with different configurations
 * (eg. built with a different compiler or linked with different versions of its dependencies).
 */
abstract class Package {
  type Version <: tix.Version
  // type PackageVersion <: itf.PackageVersion
  type Factory = (Config => PackageVersion)

  val name = {
    // Class name for singleton s is 's$'
    val className = this.getClass.getSimpleName
    assert(className endsWith "$",
      "Class name doesn't match Scala singleton class names: " + className)
    className.substring(0, className.length - 1)
  }

  trait PackageVersion extends itf.PackageVersion {
    val name = Package.this.name
    def sourceDir() = {
      val d = new File(Global.sourceDir, name)
      assert(version != null)
      new File(d, version.toString)
    }
    def buildDir() = new File(new File(Global.buildDir, name), version.toString)
    def installDir() = new File(new File(Global.installDir, name), version.toString)
    def tmpDir() = new File(new File(Global.tmpDir, name), version.toString)
  }

  trait AutotoolsPackageVersion extends PackageVersion with itf.AutotoolsPackageVersion {
    val sourcePackage: File
    override def configureFlags(): List[String] = List()

    override val workflow = () => new AutotoolsWorkflow(this)

    override def toString(): String = {
      return "%s.PackageVersion(config=%s, version=%s)" format (name, config, version)
    }
  }

  /** All known versions of this package. */
  val versions: List[Class[_ <: Any]]

  val factories: Map[Version, Factory] = null

  /** Currently installed versions of this package. */
  val installed: Map[Version, PackageVersion]

  override def toString(): String = {
    "%s(versions=[%s])".format(
      name,
      if (factories == null) "" else (factories.keys mkString ","))
  }

  PackageUniverse.packages += name -> this
}

object PackageUniverse {
  /** All known packages in the universe. */
  val packages: collection.mutable.Map[String, Package] = collection.mutable.Map()
}
